
import pandas as pd
import seaborn as sns
import warnings
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

warnings.filterwarnings('ignore')

train=pd.read_csv(r'train.csv')
test=pd.read_csv(r'test.csv')
PassengerId=test['PassengerId']
all_data = pd.concat([train, test], ignore_index = True)

#总体预览
#train.head()
#train.info()
#train.describe()

#Sex性别 结论：女性的获救率高于男性许多。
sns.barplot(x="Sex",y="Survived",data=train)
#Pclass舱位等级（头等舱/2等舱/3等舱） 结论：2号舱获救率较高
sns.barplot(x="Pclass",y="Survived", data=train)
#Age年龄 结论：获救率高的年龄段：0-12岁，30-40岁，50-57岁
facet = sns.FacetGrid(train, hue="Survived",aspect=2)
facet.map(sns.kdeplot,'Age',shade= True)
facet.set(xlim=(0, train['Age'].max()))
facet.add_legend()
#SibSp兄弟姐妹的数量 结论：独自一人的获救率是较低的，其次兄弟姐妹多了获救率也低，1-2人获救率较高
sns.barplot(x="SibSp",y="Survived",data=train)
#Parch父母孩子的数量 结论：有1-3个父母/孩子的获救率较高
sns.barplot(x="Parch",y="Survived",data=train)
#Fare票价可以看到数据大都分布在0-100这个区间内，100以上的基本都获救了
#票价为18以下的获救率是比较低的，这个和舱位等级呈现出同样的趋势。
facet = sns.FacetGrid(train, hue="Survived",aspect=2)
facet.map(sns.kdeplot,'Fare',shade= True)
facet.set(xlim=(0, train['Fare'].max()))
facet.add_legend()
#Embarked港口 结论：港口生获救率是 2&gt;1&gt;3
sns.barplot(x='Embarked',y='Survived',data=train)
#------以上为数据大致查看


#缺失值填充
#将Age中缺失的值用平均值补充
train['Age'] = train['Age'].fillna(train['Age'].mean())
#Embarked是分类数据，缺失量较少，可以使用其众数来进行填充。
mode = train['Embarked'].mode().values[0]
train['Embarked'] = train['Embarked'].fillna(mode)


#数据编码
#对数据采用独热编码（one-hot Encoding）
features = ["Pclass", "Sex","Age", "SibSp", "Parch","Fare","Embarked"]
train_data = pd.get_dummies(train[features])

print("train_data",train_data)

#划分训练集和测试集
train_label = train['Survived']
train_X,test_X,train_y,test_y = train_test_split(train_data,train_label,test_size=0.2,random_state=666)


#使用KNN进行分类
knn_clf = KNeighborsClassifier()
knn_clf.fit(train_X, train_y)
print(knn_clf.score(test_X,test_y)) #out:0.6983

#使用逻辑回归进行分类
log_reg = LogisticRegression()
log_reg.fit(train_X, train_y)
print(log_reg.score(test_X,test_y)) #out:0.7765
#我们发现逻辑回归的准确率更高一些，这时候可以对上面的算法再进行调参，
#使得准确率更大。这里我们针对逻辑回归进行优化。

# 为逻辑回归添加多项式项的管道
def PolynomialLogisticRegression(degree):
    return Pipeline([
        ('poly', PolynomialFeatures(degree=degree)),
        ('std_scaler', StandardScaler()),
        ('log_reg', LogisticRegression())
    ])
# 使用管道得到对象
#通过调整degree（多项式项数），调整为4的时候，准确率为83%。
poly_log_reg = PolynomialLogisticRegression(degree=4)
poly_log_reg.fit(train_X, train_y)
print(poly_log_reg.score(test_X, test_y)) #out:0.8324

#采用交叉验证再次来验证我们的模型准确率
from sklearn.model_selection import cross_val_score
import numpy as np
scores = cross_val_score(poly_log_reg,train_X,train_y)
np.mean(scores) #0.8061
#交叉验证后的平均准确率是80.61%，准确率还可以。

#测试数据预测
test_sets=pd.read_csv("test.csv")
test_data = test_sets[features]
test_data.info()

#缺失值处理(测试集缺失Age和Fare特征)
test_data['Age'] = test_data['Age'].fillna(test_data['Age'].mean())
test_data['Fare'] = test_data['Fare'].fillna(test_data['Fare'].mean())
test_data.info()

#独热编码
test_data_v2 = pd.get_dummies(test_data)
test_data_v2.head()

#输出预测文件
predictions = poly_log_reg.predict(test_data_v2)
output = pd.DataFrame({'PassengerId': test_sets.PassengerId, 'Survived': predictions})
output.to_csv('my_submission_2.csv', index=False)
print(" Your submission was successfully saved! ")